/*
 * InstanceLocator.java
 *
 * $Id: InstanceLocator.java,v 1.1 2008-06-26 10:42:17 mario Exp $
 */
package org.ceteca.explica.core.util;

import java.lang.reflect.Method;

import org.apache.log4j.Logger;

/**
 * Utility class for building a valid instance for a class, given the
 * classname. It uses the Java reflection to get the unique instance
 * (if the selected class implements the singleton pattern), or create
 * a new instance for the selected class.
 * <br/>
 * Responsibilities:
 * <ul>
 * 	<li>Providing a valid instance for a class. </li>
 * </ul>
 * <br/>
 * @author Mario García García <mario@imagos.es>
 * Copyright (c) 2008 Fundación Centro Tecnolóxico da Carne
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * <br/>
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * <br/>
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
public class InstanceLocator {
	/**
	 * Constant value with the logging message for an error ocurred during the 
	 * loading of the entity's helper class.
	 */
	public static final String ERROR_NOCLASS = "Cannot find the class!";
	/**
	 * Constant value with the logging message for an error ocurred during the 
	 * instantiation of the entity's helper class.
	 */
	public static final String ERROR_NOINSTANCE = "An instance of the class couldn't be created!";
	
	private Logger logger;
	
	public InstanceLocator(Logger logger) {
		this.logger = logger;
	}
	
	public Object getClassInstance(String classname) {
		return this.getInstance(
				this.getClass(classname));
	}
	
	/**
	 * Gets the class definition object for a valid class name.
	 * @param classname String, complete class name of the class to find.
	 * @return Class, class found, null if no class was found for the 
	 * provided name.
	 */
	private Class getClass(String classname) {
		Class cl = null;
		try {
			cl = Class.forName(classname);
		} catch (ClassNotFoundException e) {
			cl = null;
			this.logger.error(ERROR_NOCLASS, e);
		} catch (SecurityException e) {
			cl = null;
			this.logger.error(ERROR_NOCLASS, e);
		}
		
		this.logger.debug("Got class: " + cl);
		
		return cl;
	}
	
	/**
	 * Gets a valid instance of the chosen class. It may get the unique
	 * instance of the class (if the class implements the singleton pattern) 
	 * or create a new instance.
	 * @param cl Class, selected class to instance.
	 * @return Object, instance of the class.
	 */
	private Object getInstance(Class cl) {
		Object object = null;
		
		// Get an instance of the class
		try {
			// First try to get the instance from a singleton method
			Method singletonMethod = cl.getMethod("getInstance", (Class[]) null);
			object = singletonMethod.invoke(null, (Object[]) null);
		} catch (NoSuchMethodException nsmEx) {
			// The class doesn't implement the singleton method so that
			// create a new instance of the class
			try {
				object = cl.newInstance();
			} catch (Exception ex) {
				object = null;
				this.logger.error(ERROR_NOINSTANCE, ex);
			}
		} catch (Exception ex) {
			object = null;
			this.logger.error(ERROR_NOINSTANCE, ex);
		}
		
		this.logger.debug("Got entity helper instance: " + object);
		
		return object;
	}
	
	/**
	 * Returns tag Id assigned to CVS source file.
	 */
	public static String getRevision() {
		return "$Id: InstanceLocator.java,v 1.1 2008-06-26 10:42:17 mario Exp $";
	}
}
